﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Dominio;
using System.Net.Mail;
using System.Net;
using System.Data.Objects;

namespace CapaAccesoADatos
{
    public class Datos : IDatos
    {
        static private IDatos instance = null;

        private TiendaEntities context = new TiendaEntities();

        private Datos()
        {
            AdministracionHandler aH = AdministracionHandler.getInstance();
            aH.setDatosInstance(this);
            CompraHandler cH = CompraHandler.getInstance();
            cH.setDatosInstance(this);
            GerenciaHandler gH = GerenciaHandler.getInstance();
            gH.setDatosInstance(this);

        }
        static public IDatos getInstance()
        {
            if (instance == null)
            {
                instance = new Datos();
            }
            return instance;
        }

        public int cantProductos()
        {
            var q = from p in context.Producto
                    select p;
            return q.Count();
        }

        #region Categoria

        public void altaCategoria(BLCategoria blc)
        {

            Categoria c = new Categoria();
            mapearBLCategoria(blc, c);
            context.AddToCategoria(c);
            c.CatEstado = 1;
            context.SaveChanges();
        }

        public void modificarCategoria(BLCategoria blc)
        {
            context = new TiendaEntities();
            Categoria cat = new Categoria();
            cat = context.Categoria.First(c => c.CatId == blc.CatId);
            if (cat != null)
            {
                cat.CatDescripcion = blc.CatDescripcion;
                cat.CatEstado = blc.CatEstado;
                context.SaveChanges();
            }
        }

        public void bajaCategoria(BLCategoria blc)
        {
            context = new TiendaEntities();
            Categoria cat = context.Categoria.First(c => c.CatDescripcion == blc.CatDescripcion);
            cat.CatEstado = 0;
            context.SaveChanges();
        }

        public BLCategoria getBLCategoria(int id)
        {
            Categoria cat = context.Categoria.First(c => c.CatId == id);
            if (cat != null)
            {
                BLCategoria blc = new BLCategoria();
                mapearCategoria(blc, cat);
                return blc;
            }
            else
                return null;
        }

        public List<BLCategoria> getBLCategorias()
        {
            context = new TiendaEntities();
            List<Categoria> lst = new List<Categoria>();
            lst = context.Categoria.ToList();
            List<BLCategoria> lstcat = new List<BLCategoria>();
            foreach (Categoria c in lst)
            {
                BLCategoria cat = new BLCategoria();
                mapearCategoria(cat, c);
                lstcat.Add(cat);
            }
            return lstcat;
        }

        public List<Categoria> getCategorias()
        {
            context = new TiendaEntities();
            List<Categoria> lst = new List<Categoria>();
            lst = context.Categoria.ToList();
            return lst;
        }

        private static void mapearBLCategoria(BLCategoria blc, Categoria c)
        {
            c.CatDescripcion = blc.CatDescripcion;
            c.CatId = blc.CatId;
        }

        private static void mapearCategoria(BLCategoria blc, Categoria c)
        {
            blc.CatDescripcion = c.CatDescripcion;
            blc.CatId = c.CatId;
        }

        #endregion

        #region ABM Productos

        public void altaProducto(BLProducto blp)
        {
            context = new TiendaEntities();
            Producto p = new Producto();
            p = mapearBLProducto(blp);
            p.ProdEstado = 1;
            Categoria cat = context.Categoria.First(c => c.CatId == blp.categoria.CatId);
            cat.Producto.Add(p);

            context.AddToProducto(p);
            context.SaveChanges();
            blp.ProdId = p.ProdId;
        }

        public Producto mapearBLProducto(BLProducto blp)
        {
            context = new TiendaEntities();
            Producto p = new Producto();
            p.ProdDescripcion = blp.ProdDescripcion;
            p.ProdId = blp.ProdId;
            p.ProdNombre = blp.ProdNombre;
            p.ProdPrecio = blp.ProdPrecio;
            p.ProdFabricante = blp.ProdFabricante;
            p.ProdCodigo = blp.ProdCod;
            Categoria cat = context.Categoria.First(c => c.CatId == blp.categoria.CatId);
            p.Categoria = new Categoria();
            p.Categoria = cat;

            return p;
        }

        public BLProducto mapearProductoBL(Producto p)
        {
            context = new TiendaEntities();
            BLProducto blp = new BLProducto();
            blp.ProdDescripcion = p.ProdDescripcion;
            blp.ProdId = p.ProdId;
            blp.ProdNombre = p.ProdNombre;
            blp.ProdPrecio = (decimal)p.ProdPrecio;
            blp.ProdFabricante = p.ProdFabricante;
            blp.categoria = getBLCategoria(p.Categoria.CatId);
            blp.ProdCod = p.ProdCodigo;

            return blp;
        }

        public void modificarProducto(BLProducto blp)
        {
            context = new TiendaEntities();
            Producto p = context.Producto.Include("Producto.Categoria").First(prod => prod.ProdId == blp.ProdId);
            if (p != null)
            {
                Categoria c = context.Categoria.First(cat => cat.CatId == blp.categoria.CatId);
                p.ProdNombre = blp.ProdNombre;
                p.ProdDescripcion = blp.ProdDescripcion;
                p.ProdFabricante = blp.ProdFabricante;
                p.ProdPrecio = blp.ProdPrecio;
                p.ProdCodigo = blp.ProdCod;
                c.Producto.Load();
                p.Categoria = c;
                context.SaveChanges();
            }
        }

        public void agregarVideo_Producto(int idProd, Byte[] video)
        {
            context = new TiendaEntities();
            Producto p = getProducto(idProd);
            if (p != null)
            {
                p.ProdVideo = video;
                context.SaveChanges();
            }
        }

        public void eliminarVideo_Producto(int idProd)
        {
            context = new TiendaEntities();
            Producto p = getProducto(idProd);
            if (p != null)
            {
                p.ProdVideo = null;
                context.SaveChanges();
            }
        }

        public void bajaProducto(int idProd)
        {
            context = new TiendaEntities();
            Producto p = getProducto(idProd);
            p.ProdEstado = 0;
            context.SaveChanges();

        }

        public Producto getProducto(int id)
        {
            Producto p = context.Producto.First(prod => prod.ProdId == id);
            if (p != null)
            {
                return p;
            }
            else
            {
                return null;
            }
        }

        public BLProducto getBLProducto(int id)
        {
            Producto p = context.Producto.Include("Categoria").First(prod => prod.ProdId == id);
            if (p != null)
            {
                BLProducto blp = mapearProductoBL(p);
                return blp;
            }
            else
            {
                return null;
            }
        }

        public List<BLProducto> getBLProductos()
        {
            context = new TiendaEntities();
            List<Producto> lst = new List<Producto>();
            lst = context.Producto.Include("Categoria").ToList();
            List<BLProducto> lstprod = new List<BLProducto>();
            foreach (Producto p in lst)
            {
                BLProducto blp = mapearProductoBL(p);
                lstprod.Add(blp);
            }
            return lstprod;
        }

        public List<BLProducto> visualizarCatalogo(int idCat)
        {
            context = new TiendaEntities();
            List<Producto> lst = new List<Producto>();
            lst = context.Producto.ToList();
            List<BLProducto> lstprod = new List<BLProducto>();
            foreach (Producto p in lst)
            {
                if (p.Categoria.CatId == idCat)
                {
                    BLProducto blp = new BLProducto();
                    mapearProductoBL(p);
                    lstprod.Add(blp);
                }
            }
            return lstprod;
        }

        public List<ProductoVendido> nProductos(int n)
        {
            ObjectQuery<Productos_Comprados> pcs = context.Productos_Comprados;

            var query = (from pc in context.Productos_Comprados
                         group pc by pc.ProdCompNombre into pcGroup
                         select new { pcNombre = pcGroup.Key, Ventas = pcGroup });

            List<ProductoVendido> lista = new List<ProductoVendido>();
            float sum = 0;
            foreach (var pcGroup in query)
            {
                foreach (var venta in pcGroup.Ventas)
                {
                    sum = sum + (float)venta.ProdCompPrecio;
                }
                lista.Add(new ProductoVendido() { Producto = pcGroup.pcNombre, Facturacion = sum });
                lista.Sort(ordenarPorFacturacion);
                lista.OrderByDescending(Fac => Fac.Facturacion);
            }

            return lista;
        }

        private int ordenarPorFacturacion(ProductoVendido p1, ProductoVendido p2)
        {
            return p2.Facturacion.CompareTo(p1.Facturacion);
        }

        public List<CategoriaVendida> analisisVentas(DateTime fchini, DateTime fchfin)
        {

            var query = (from pc in context.Productos_Comprados.Include("Compra")
                         where pc.Compra.FchCompra >= fchini && pc.Compra.FchCompra <= fchfin
                         group pc by pc.ProdCompCatId into pcGroup
                         select new { pcCatID = pcGroup.Key, Ventas = pcGroup });

            List<CategoriaVendida> lista = new List<CategoriaVendida>();

            float sum = 0;

            foreach (var pcGroup in query)
            {
                foreach (var venta in pcGroup.Ventas)
                {
                    sum = sum + (float)venta.ProdCompPrecio;
                }
                Categoria c = context.Categoria.First(cat => cat.CatId == pcGroup.pcCatID);
                lista.Add(new CategoriaVendida() { Categoria = c.CatDescripcion  , Participacion = sum });
                lista.Sort(ordenarPorParticipacion);
                lista.OrderByDescending(Fac => Fac.Participacion);
            }

            float sumaP1 = 0;
            foreach (CategoriaVendida item in lista)
            {
                sumaP1 = sumaP1 + item.Participacion;
            }
            
            foreach (CategoriaVendida item in lista)
            {
                item.Participacion = (item.Participacion / sumaP1)*100;
            }

            
            return lista;
        }
        
        private int ordenarPorParticipacion(CategoriaVendida c1, CategoriaVendida c2)
        {
            return c2.Participacion.CompareTo(c1.Participacion);
        }    
        //    context = new TiendaEntities();
        //    List<string> lst = new List<string>();
        //    List<Productos_Comprados> lstprod = new List<Productos_Comprados>();
        //    lstprod = context.Productos_Comprados.ToList();
        //    List<Compra> lstcom = new List<Compra>();
        //    lstcom = context.Compra.ToList();
        //    int i = 0;
        //    foreach (Compra c in lstcom)
        //    {
        //        if (c.FchCompra >= fchini && c.FchCompra <= fchfin)
        //        {
        //            foreach (Productos_Comprados pc in lstprod)
        //            {
        //                // Agrego los productos comprados por el id de categoria de prod, poniendo id, nombre y cantidad, precio y categoria
        //                i = i + 1;
        //            }
        //        }
        //    }
        //    // ordeno la lista o la devuelvo asi???
        //    return lst;
        //}

        #endregion

        public void agregarProductoACarrito(string usuario, int codProducto)
        {
            TiendaEntities context = new TiendaEntities();
            Usuario u = context.Usuario.First(user => user.UsuUsuario == usuario);
            Producto p = context.Producto.Include("Categoria").First(prod => prod.ProdId == codProducto);

            int idUser = (from c in context.Usuario
                          where c.UsuUsuario == usuario
                          select c).First().UsuId;

            //TODO: Ver caso en que se quiere agregar mas cantidad de un producto.
            if (u.Carrito_Compra.Count == 0)
            {
                Carrito_Compra cc = new Carrito_Compra();
                cc.Producto = p;
                cc.Usuario = u;
                cc.CarritoCant = 1;
                u.Carrito_Compra.Add(cc);

                context.AddToCarrito_Compra(cc);
            }
            else
            {
                u.Carrito_Compra.First().CarritoCant++;
            }

            context.SaveChanges();
        }

        public void registrarUsuario(BLUsuario u)
        {
            Usuario us = new Usuario();

            us = mapearBLUsuario(u);

            context.AddToUsuario(us);
            context.SaveChanges();
        }

        private Usuario mapearBLUsuario(BLUsuario u)
        {
            Usuario us = new Usuario();
            us.UsuNombre = u.Nombre;
            us.UsuApellido = u.Apellido;
            us.UsuDireccion = u.Direccion;
            us.UsuEmail = u.Email;
            us.UsuUsuario = u.Usuario;
            us.UsuPassword = u.Contraseña;
            us.UsuTelefono = u.Telefono;
            return us;
        }

        private BLUsuario mapearUsuarioBL(Usuario us)
        {
            BLUsuario u = new BLUsuario();
            u.Nombre = us.UsuNombre;
            u.Apellido = us.UsuApellido;
            u.Direccion = us.UsuDireccion;
            u.Email = us.UsuEmail;
            u.Usuario = us.UsuUsuario;
            u.Contraseña = us.UsuPassword;
            u.esAdmin = false;
            if (us.UsuAdm == 1)
                u.esAdmin = true;
            u.esGerente = false;
            if (us.UsuGte == 1)
                u.esGerente = true;
            u.Telefono = us.UsuTelefono;
            return u;
        }

        public void modificarUsuario(BLUsuario u)
        {
            context = new TiendaEntities();
            Usuario usu = context.Usuario.First(user => user.UsuUsuario == u.Usuario);
            if (usu != null)
            {
                usu = mapearBLUsuario(u);
                context.SaveChanges();
            }
        }

        public void bajaUsuario(BLUsuario u)
        {
            Usuario usu = context.Usuario.First(user => user.UsuUsuario == u.Usuario);
            if (usu != null)
            {
                usu.UsuEstado = 0;
                context.SaveChanges();
            }

        }
        public BLUsuario getUsuarioPorUserName(String usuario)
        {

            Usuario u = context.Usuario.First(user => user.UsuUsuario == usuario && user.UsuEstado == 1);
            BLUsuario u_bl;
            u_bl = mapearUsuarioBL(u);

            return u_bl;
        }

        public List<BLUsuario> getBLUsuarios()
        {
            context = new TiendaEntities();
            List<Usuario> list = context.Usuario.ToList();
            List<BLUsuario> listBL = new List<BLUsuario>();

            foreach (Usuario u in list)
            {
                listBL.Add(mapearUsuarioBL(u));
            }
            return listBL;
        }
        #region Compra

        public void agregarCompra(DateTime fecha, string direccion, string telefono, String blu)
        { 
            int i = 0;
            Usuario u = context.Usuario.First(user => user.UsuUsuario == blu);
            Compra com = new Compra();
            com.CompTelefono = telefono;
            com.CompDirEntrega = direccion;
            com.FchCompra = fecha;
            com.Usuario = u;
            context.AddToCompra(com);

            //context.SaveChanges();
            string texto = direccion + " ";
            var lcarrito = (from c in context.Carrito_Compra
                            where c.Usuario.UsuUsuario == u.UsuUsuario
                            select c);

            foreach (Carrito_Compra cp in lcarrito)
            {
                Producto p = context.Producto.Include("Categoria").First(prod => prod.ProdId == cp.ProdId);

                Categoria c = context.Categoria.First(cat => cat.CatId == p.Categoria.CatId);
                Productos_Comprados pc = new Productos_Comprados();
                //pc.CompId = com.CompId;
                pc.ProdCompId = i + 1;
                pc.ProdCompCatId = p.Categoria.CatId;
                pc.ProdCompDesc = p.ProdDescripcion;
                texto = texto + p.ProdDescripcion + " ";
                pc.ProdCompFabricante = p.ProdFabricante;
                pc.ProdCompNombre = p.ProdNombre;
                pc.ProdCompVideo = p.ProdVideo;
                pc.ProdCompPrecio = p.ProdPrecio;
                pc.ProdCompCod = p.ProdCodigo;
                pc.ProdCompCant = cp.CarritoCant;
                com.Productos_Comprados.Add(pc);
                context.AddToProductos_Comprados(pc);
                //context.SaveChanges();
                i = i + 1;
            }

            try
            {
                context.SaveChanges();
            }
            catch 
            {

            }
            
            //Confirmacion de Mail, se envia desde tallerort2010.gmail, contraseña JJM2010ort, desde el puerto 587
            MailMessage msg = new MailMessage();
            msg.To.Add(new MailAddress("tallerort2010@gmail.com"));
            msg.From = new MailAddress("tallerort2010@gmail.com");
            msg.Subject = "Confirmacion de Compra";
            msg.Body = "Prueba";// texto;

            SmtpClient clienteSmtp = new SmtpClient("smtp.gmail.com");
            clienteSmtp.Credentials = new NetworkCredential("tallerort2010@gmail.com", "JJM2010ort");

            try
            {
                clienteSmtp.Send(msg);
            }
            catch 
            {

            }

        }

        #endregion

        #region Miembros de IDatos


        public void eliminarCarrito(BLUsuario u)
        {
            Usuario usu = context.Usuario.First(user => user.UsuUsuario == u.Usuario);

            var q = (from c in context.Carrito_Compra
                     where c.Usuario.UsuUsuario == usu.UsuUsuario
                     select c);

            foreach (Carrito_Compra ca in q)
            {
                context.DeleteObject(ca);
            }
            context.SaveChanges();
        }

        #endregion



        #region Miembros de IDatos


        public int getCantProductosAgregados(string userName1, int productoID1)
        {
            Usuario usu = context.Usuario.First(user => user.UsuUsuario == userName1);
            Carrito_Compra cc = context.Carrito_Compra.First(carrito => carrito.ProdId == productoID1 && carrito.UsuId == usu.UsuId);
            return (int)cc.CarritoCant;
        }

        #endregion

        public BLCarritoCompra getCarritoCompra(string username)
        {
            Usuario usu = context.Usuario.First(user => user.UsuUsuario == username);

            List<Carrito_Compra> cc1 = (from c in context.Carrito_Compra.Include("Producto")
                                        where c.UsuId == usu.UsuId
                                        select c).ToList();

            BLCarritoCompra blc = new BLCarritoCompra();

            blc.listaProductos = new Dictionary<BLProducto, int>();

            foreach (Carrito_Compra cc in cc1)
            {
                blc.listaProductos.Add(mapearProductoBL(cc.Producto), ((int)cc.CarritoCant));
                blc.usuario = getUsuarioPorUserName(username);

            }

            return blc;

        }
    }
}

